import { type } from "os";

// 基本类型
{
  // 一 interface和type的区别
  // 1-继承区别
  interface Person {
    name: string;
    sex: string;
  }
  interface Women extends Person {
    like: string;
  }

  type Animal = {
    name: string;
  };
  type Bear = Animal & {
    honey: boolean;
  };
  // 2-拓展属性
  // 重复命名会添加或者覆盖属性
  interface Women {
    boyFriend: boolean;
  }
  // type只能用新的变量定义

  // 二 类型断言
  const myCanvas = document.getElementById("canvas") as HTMLElement;
  const myCanvas1 = <HTMLElement>document.getElementById("canvas");
  const str = "hello" as string;

  // 文字类型
  // 1
  function printText(s: string, alias: "left" | "right" | "center") { }
  printText("hello", "left");
  // 2
  function compare(num1: number, num2: number): 0 | 1 | -1 {
    return num1 === num2 ? 0 : num1 > num2 ? 1 : -1;
  }
  // 3
  interface Option {
    width: number;
  }
  function config(x: Option | "auto") { }
  config({
    width: 100,
  });
  config("auto");
  // 4
  let b1: true = true; // 只能赋值为true

  // 三 null 和 undefined
  // let z: string = undefined; 报错的
  function live(x?: number | null | undefined) {
    // x是绝对存在的并且不是null和undefined
    console.log(x!.toFixed());
  }

  // 四 枚举
  enum Direction {
    Up = 1,
    Down,
    Left,
    Right,
  }
  let num = Direction.Up; // 1

  // 五 symbol
  const firstName = Symbol("name"); // 唯一值
  const secondName = Symbol("name"); // 唯一值
  // if (firstName === secondName) { false

  // }

  // 六 类型守卫typeof

  // 七 判断真假
  // 0 NaN "" null undefined 为false
  // Boolean() !!

  // 八 等值缩小
  function example(x: string | number, y: number | boolean) {
    if (x === y) {
    }
  }

  // 九 in操作符
  type Fish = { swim: () => void };
  type Bird = { fiy: () => void };
  type Human = { swim?: () => void; fiy?: () => void };
  function move(animal: Fish | Bird | Human) {
    if ("swim" in animal) {
      return (animal as Fish).swim();
    }
    return (animal as Bird).fiy();
  }

  // 十 is类型保护 类型谓词
  function isString(test: any): test is string {
    return typeof test === "string";
  }

  function example1(foo: any) {
    // 确定foo是string类型
    if (isString(foo)) {
      console.log("it is a string" + foo);
      console.log(foo.length); // string function
      // 如下代码编译时会出错，运行时也会出错，因为 foo 是 string 不存在toExponential方法
      // console.log(foo.toExponential(2));
    }
    // 编译不会出错，但是运行时出错
    console.log(foo.toExponential(2));
  }
  example1("hello world");

  // 十一 unions 联合类型
  // 十二 never
}

// 函数
{
  // 一 函数类型表达式
  function greeter(fn: (a: string) => void) {
    fn("hello");
  }

  // 二 调用签名
  type descFun = {
    // 是一个方法，但是有自己的属性
    description: string;
    (someArg: string): boolean;
  };
  function doSomething(fn: descFun) {
    console.log(fn.description, fn("hello"));
  }

  // 三 构造签名 看不懂~

  // 四 泛型函数
  // 泛型指的是Type
  function firstElement<Type>(arr: Type[]): Type | undefined {
    return arr[0];
  }
  firstElement<number>([1, 2, 3]);
  firstElement(["1", "2", "3"]);

  function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
    return arr.map(func);
  }
  const res = map([1, 2, 3], (n) => n * 2);

  // 五 限制条件
  function longest<Type extends { length: number }>(a: Type, b: Type): Type {
    return a.length >= b.length ? a : b;
  }

  // 六 泛型函数-指定类型参数
  function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
    return arr1.concat(arr2);
  }
  const res1 = combine<string | number>(["1", "2"], [1, 2, 3]);

  // 七 可选参数
  function fn1(n?: number) {
    console.log(n?.toFixed());
  }
  fn1(1.1);
  fn1();

  // 八 函数重载
  function makeDate(timestamp: number): Date; // 重载签名
  function makeDate(m: number, d: number, y: number): Date; // 重载签名
  // 实现签名 要去兼容重载签名
  function makeDate(m: number, d?: number, y?: number): Date {
    if (d && y) {
      return new Date(m, d, y);
    }
    return new Date(m);
  }

  function fn2(n: string): string;
  function fn2(n: number): number;
  function fn2(n: string | number): any { }
}

// 其他类型
{
  // void
  function noop() {
    return;
  }
  // object: string number bigint boolean symbol null undefined  不同于{}，不同于Object
  // unknown 表示任何值，对于未知的unknown做任何值都是不合法的
  // never 永远不会被观察到的值
  function fail(msg: string): never {
    throw new Error(msg);
  }
  function fn3(x: string | number) {
    if (typeof x === "string") {
    } else if (typeof x === "number") {
    } else {
      // x never
    }
  }
  // Function

  // others
  // 一 参数展开运算符
  function multiply(n: number, ...m: number[]) { }
  multiply(10, 1, 2, 3, 4);

  let arr1 = [1, 2, 3];
  let arr2 = [4, 5, 6];
  arr1.push(...arr2); // [1,2,3,4,5,6]

  // 二 参数结构
  type ABC = {
    a: number;
    b: number;
    c: number;
  };
  function sum({ a, b, c }: ABC) { }

  // 三 返回void类型
  // 当一个字面的函数定义一个void的返回类型时，该函数必须不返回任何值
  type voidFun = () => void;
  let voidFun1: voidFun = () => true; // 虽然可以这么写，但是实际上执行的时候返回的还是void
}

// 对象类型
{
  // 可以使用interface和type去定义一个对象
  interface IPerson {
    name: string;
    age: number;
  }
  type Person = {
    name: string;
    age?: number; // 可选属性
    readonly prop: string; // 只读属性
    readonly home: {
      // 不能更改
      count: number; // 可以改变
      readonly name: number; // 不可以改变
    };
  };
  // 索引签名
  interface StringArray {
    [index: number]: string; // 索引类型只能是number或者string类型
  }
  const myArray: StringArray = ["a", "b"];
  myArray[0];

  interface TestArray {
    [key: string]: number;
  }
  const testArray: TestArray = {
    x: 1,
    y: 2,
  };

  interface Not {
    [index: string]: number | string;
    readonly length: number;
    name: string;
  }
  const not: Not = {
    x: 1,
    length: 1,
    name: "name",
  };

  // 拓展签名
  // interface 使用extends
  // type 使用&

  // 交叉类型
  interface Colorful {
    color: string;
  }
  interface Circle {
    radius: number;
  }
  // type类型结合interface类型
  type ColorfulCircle = Colorful & Circle;

  // 接口与交叉类型的区别 ******
  // 报错 只能通过交叉形式拓展签名
  // type a = {

  // }
  // type a = {

  // }
  // 不报错 interface可以重复定义
  interface b { }
  interface b { }

  // 泛型对象类型
  interface Box<Type> {
    contain: Type;
  }
  let box1: Box<string> = {
    contain: "aaa",
  };

  type Box1<Type> = {
    content: Type;
  };
  let box2: Box1<number> = {
    content: 1,
  };
}

// 类型操纵
{
  // 泛型类
  class GeneNumber<Type> {
    value: Type;
    add: (x: Type, y: Type) => Type;
    constructor(value: Type, add: () => Type) {
      this.value = value;
      this.add = add;
    }
  }
  // 泛型约束中使用类型参数
  // Key是Type的某个属性的key
  function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
    return obj[key];
  }
  let x = {
    a: 1,
    b: 2,
    c: 3,
  };
  getProp(x, "a"); // 1
  // getProp(x, 'm') // 报错

  // keyof 表示是某个定义的某个属性
  type Point = { x: number; y: number };
  type P = keyof Point;
  const p1: P = "y";
  const p2: P = "x";

  type Arrays = {
    [n: number]: unknown;
  };
  const a: keyof Arrays = 1;

  // typeof 类型操作符

  // 索引访问类型
  type Person = {
    age: number;
    alive: boolean;
  };
  interface Animal {
    sex: string;
  }
  type Age = Person["age" | "alive"] | Animal["sex"]; // 三种属性的联合类型

  const array = [
    { name: "zhangsan", age: 12 },
    { name: "lisi", age: 20 },
  ];
  // type Person = {name： string, age: number}
  type Person1 = typeof array[number];

  type age = "age";
  type Age1 = age;

  // 条件类型
  interface Animal1 {
    live(): boolean;
  }
  interface Dog extends Animal1 {
    woof(): void;
  }
  type Example2 = Dog extends Animal1 ? number : string;
  type NameOrId<T extends number | string> = T extends number ? number : string;

  // 条件类型约束
  type Message<T> = T extends { message: unknown } ? T["message"] : never;

  // infer 表示返回值类型
  type GetRType<Type> = Type extends (...args: never[]) => infer R ? R : never;
  // type Num = number
  type Num = GetRType<() => number>;
  let num: Num = 11;
  type Bolos = GetRType<() => boolean[]>;
  let bolos: Bolos = [true, false];
  type Never = GetRType<string>;
  let never: Never = null as never;

  // 分布式条件类型
  type ToArray<Type> = Type extends any ? Type[] : never;
  type strOrNum = ToArray<string | number>;
  let rs2: strOrNum = [11, 11];
  let rs3: strOrNum = ["11", "11"];
}

// 类
// 六种类成员
class Point1 {
  x: number = 0; // 默认为0
  readonly y: number = 0;
  // 初始化定义
  // 构造函数不能有类型参数，不能有返回类型注释
  constructor(x: number = 1, y: number) {
    // 带默认值
    this.x = x;
    this.y = y; // 只读属性只可以被类的初始化函数里面被二次定义
  }
}
class Point2 extends Point1 {
  // 数据劫持
  _length = 0;
  get length() {
    return this._length;
  }
  set length(n: number) {
    this._length = n;
  }
  constructor(x: number, y: number) {
    super(x, y);
  }
}

// 索引签名
class myClass {
  [s: string]: boolean | ((s: string) => boolean);
  check(s: string) {
    return this[s] as boolean;
  }
}
// 类的继承
interface Pingable {
  ping(): void;
}
// 使用implements继承接口或者类
class Sonar implements Pingable {
  ping(): void {
    console.log(111);
  }
}

// 使用extends继承类
class Sonar1 extends Sonar {

}

// 重写类的方法 做类型兼容
// 初始化顺序
class Base {
  name = 'base'
  constructor() {

  }
}
class Derived extends Base {
  name = 'derived';
  constructor() {
    super();
    super.name = '1';
  }
}
// name = 'derived' 最后的name

// 继承内置类型
{// 成员的可见性
  class seeClass {
    public name: string; // 任何对象在任何地方都可以使用
    protected age: number; // 只在当前类或者子类中访问
    private sex: string; // 只能在当前类中使用
  }
  class AA {
    private x = 10;
    private sameX(others: AA) {
      return this.x === others.x
    }
  }

  // 静态成员 BB公用静态成员
  class BB {
    static x = 0
    private static b = 1;
    static printX() {
      BB.x
      BB.b
    }
  }
  BB.x
  // BB.b 使用不了

  // 类里的static区块 不能被外部访问
  class Foo {
    static #count = 0;
    get count() {
      return Foo.#count;
    }
    static {
      try {
        Foo.#count = 1
      } catch (error) {

      }
    }
  }
  // Foo.#count 报错

  // 泛型类
  // 静态成员是不能有泛型的
  class Box11<Type>{
    contents: Type;
    constructor(value: Type) {
      this.contents = value;
    }
  }

  // 类运行的this
  class myClass11 {
    name: '11'
    getName() {
      return this.name
    }
  }
  const c = new myClass11()
  const obj = {
    name: '22',
    getName: c.getName
  }
  obj.getName() // 22 实际上想实现的是11 但是c的this指向的是obj自己
  // 解决： 箭头函数 或 this参数
  // 箭头函数
  // class myClass11 {
  //   name: '11'
  //   getName: () => {
  //     return this.name
  //   }
  // }

  // this参数
  // class myClass11 {
  //   name: '11'
  //   getName(this: myClass11) {
  //     return this.name
  //   }
  // }

  // this类型
  class B1 {
    content: string = ''
    sameAs(other: this) {
      return this.content === other.content
    }
  }
  class B2 extends B1 {
    othercontent: string = '?'
  }
  let b1 = new B1()
  let b2 = new B2();
  // b2.sameAs(b1); 报错 因为B1的this类型指向B2
  b2.sameAs(b2);

  // 参数属性
  class Param {
    constructor(public readonly x: number, protected y: number, private z: number) {
      this.x = x
      this.y = y
      this.z = z
    }
  }
  let p = new Param(1, 2, 3)
  p.x

  // 类表达式 匿名类
  const someClass = class <Type>{ }
  const m = new someClass<string>()

  // 抽象类和成员
  // 被继承 且 实现
  abstract class Base1 {
    abstract getName(): string
    printName() {
      console.log(this.getName());
    }
  }
  class Base1Son extends Base1 {
    getName(): string {
      return '11';
    }
  }

  // 类之间的关系
  // 类之间的相互替代
  class Point3 {
    x: 1
    y: 2
  }
  class Point4 {
    x: 1
    y: 2
    z: 9

  }
  const pp: Point3 = new Point4();

  class Empty {

  }
  function fn(x: Empty) {

  }
  fn(window)
  fn(1)
  fn({})
}

// 模块
